//请实现两个函数，分别用来序列化和反序列化二叉树。 
//
// 你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑，你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字
//符串反序列化为原始的树结构。 
//
// 提示：输入输出格式与 LeetCode 目前使用的方式一致，详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式，你也可以采用其他的方
//法解决这个问题。 
//
// 
//
// 示例： 
//
// 
//输入：root = [1,2,3,null,null,4,5]
//输出：[1,2,3,null,null,4,5]
// 
//
// 
//
// 注意：本题与主站 297 题相同：https://leetcode-cn.com/problems/serialize-and-deserialize-
//binary-tree/ 
// Related Topics 树 深度优先搜索 广度优先搜索 设计 字符串 二叉树 👍 260 👎 0

package com.cute.leetcode.editor.cn;

import java.util.LinkedList;
import java.util.Queue;

public class XuLieHuaErChaShuLcof {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(3);
        TreeNode node1 = new TreeNode(3);
        TreeNode node2 = new TreeNode(3);
        TreeNode node3 = new TreeNode(3);
        root.left = node1;root.right = node2;
        node1.left = node3;
        String serialize = new XuLieHuaErChaShuLcof().new Codec().serialize(root);
        TreeNode res = new XuLieHuaErChaShuLcof().new Codec().deserialize(serialize);
        System.out.println("stop");
    }
    //leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    /**
     * 看了题解，使用层序遍历添加节点，空节点也进行添加，因为要使用index取值
     * 序列化与反序列化是一一对应的
     */
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "";
        StringBuilder stringBuilder = new StringBuilder();
        Queue<TreeNode> queue = new LinkedList<TreeNode>(){{add(root);}};
        while (!queue.isEmpty()){
            TreeNode poll = queue.poll();
            if (poll != null){//层序遍历添加节点
                stringBuilder.append(poll.val).append(",");
                queue.add(poll.left);
                queue.add(poll.right);
            }else stringBuilder.append("null,");//添加空节点
        }
        return stringBuilder.toString();
    }
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if ("".equals(data)) return null;
        String[] nodes = data.split(",");
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
        Queue<TreeNode> queue = new LinkedList<TreeNode>(){{add(root);}};
        int i = 1;// 根据下标取得满二叉树的节点位置
        while (!queue.isEmpty()){
            TreeNode poll = queue.poll();
            if (!nodes[i].equals("null")){//当前节点不为空的时候需要添加节点并入队列
                poll.left = new TreeNode(Integer.parseInt(nodes[i]));
                queue.add(poll.left);
            }
            i++;
            if (!nodes[i].equals("null")){
                poll.right = new TreeNode(Integer.parseInt(nodes[i]));
                queue.add(poll.right);
            }
            i++;
        }
        return root;
    }

    /**
     * 我是这样想的，遍历root得到中序遍历和后续遍历的结果，然后按照之前的方法构建二叉树
     * 但是测试用例中存在重复元素，从中序遍历中寻找根节点时会出现一些问题
     * 所以此方法行不通
     *//*
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "";
        //按照中序遍历以及后序遍历的方式得到两部分字符串
        StringBuilder stringBuilder = new StringBuilder();
        midOrder(root, stringBuilder);
        stringBuilder.deleteCharAt(stringBuilder.length()-1);
        stringBuilder.append("/");
        postOrder(root, stringBuilder);
        stringBuilder.deleteCharAt(stringBuilder.length()-1);
        return stringBuilder.toString();
    }
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if ("".equals(data)) return null;
        String[] split = data.split("/");
        String[] inorder = split[0].split(",");
        String[] postorder = split[1].split(",");
        return builder(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }

    public void midOrder(TreeNode node, StringBuilder stringBuilder){
        if (node.left != null) midOrder(node.left, stringBuilder);
        stringBuilder.append(node.val).append(",");
        if (node.right != null) midOrder(node.right, stringBuilder);
    }
    public void postOrder(TreeNode node, StringBuilder stringBuilder){
        if (node.left != null) postOrder(node.left, stringBuilder);
        if (node.right != null) postOrder(node.right, stringBuilder);
        stringBuilder.append(node.val).append(",");
    }
    public TreeNode builder(String[] inorder, int inStart, int inEnd, String[] postorder, int postStart, int postEnd){
        if (postStart == postEnd) return null;
        String val = postorder[postEnd - 1];
        TreeNode root = new TreeNode(Integer.parseInt(val));
        if (postEnd - postStart == 1) return root;
        int index = inEnd-1;
        for (; index >= inStart; index--) if (inorder[index].equals(val)) break;

        int inorderLeftStart = inStart;
        int inorderLeftEnd = index;
        int postorderLeftStart = postStart;
        int postorderLeftEnd = postorderLeftStart + inorderLeftEnd - inorderLeftStart;

        int inorderRightStart = index + 1;
        int inorderRightEnd = inEnd;
        int postOrderRightStart = postorderLeftEnd;
        int postOrderRightEnd = postEnd - 1;
        root.left = builder(inorder, inorderLeftStart, inorderLeftEnd, postorder, postorderLeftStart, postorderLeftEnd);
        root.right = builder(inorder, inorderRightStart, inorderRightEnd, postorder, postOrderRightStart, postOrderRightEnd);
        return root;
    }*/
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));
//leetcode submit region end(Prohibit modification and deletion)
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }
}